#include "esp_log.h"
#include "AsyncClient.hpp"
#include "AsyncServer.hpp"
#include "AsyncTCP.hpp"

#define TAG "Async"

/// @brief 获取系统启动以来的毫秒数
/// @return 系统启动以来的毫秒数
uint32_t get_ms_since_start()
{
    return xTaskGetTickCount() * portTICK_PERIOD_MS;
}

/// @brief 超时检测
/// @param start_time 开始时间
/// @param timeout 超时阀值
bool is_timeout(uint32_t start_time, uint32_t timeout)
{
    if (timeout > 0) {
        return ((int32_t)(get_ms_since_start() - start_time)) >= ((int32_t)timeout);
    }
    return false;
}

/// @brief 关闭tcp连接
/// @param pcb 连接关联的协议控制块
/// @return 成功关闭时返回ESP_OK
err_t close_tcp(tcp_pcb* pcb)
{
    if (pcb == nullptr) {
        ESP_LOGE(TAG, "pcb 参数错误");
        return ESP_ERR_INVALID_ARG;
    }
    tcp_api_call_t msg;
    msg.pcb = pcb;
    auto err = tcpip_api_call([](tcpip_api_call_data * data) -> err_t {
        return tcp_close(reinterpret_cast<tcp_api_call_t*>(data)->pcb);
    },
    (tcpip_api_call_data*)&msg
                             );
    return err;
}

/// @brief 强制断开连接
/// @param pcb 连接关联的协议控制块
void abort_tcp(tcp_pcb* pcb)
{
    if (pcb == nullptr) {
        ESP_LOGE(TAG, "pcb 参数错误");
        return;
    }
    tcp_api_call_t msg;
    msg.pcb = pcb;
    tcpip_api_call([](tcpip_api_call_data * data) -> err_t {
        tcp_abort(reinterpret_cast<tcp_api_call_t*>(data)->pcb);
        return ERR_OK;
    },
    (tcpip_api_call_data*)&msg
                  );
}

Async::Async()
    : m_async_queue(nullptr)
    , m_event_pool(nullptr)
    , m_async_task(nullptr)
{
    m_async_queue = xQueueCreate(CONFIG_EVENTS_QUEUE_LEN, sizeof(lwip_event_t *));
    if (m_async_queue == nullptr) {
        ESP_LOGE(TAG, "创建LWIP事件队列失败.");
        return;
    }

    m_event_pool = xQueueCreate(CONFIG_EVENTS_QUEUE_LEN, sizeof(lwip_event_t *));
    if (m_event_pool == nullptr) {
        ESP_LOGE(TAG, "创建LWIP事件池失败.");
        vQueueDelete(m_async_queue);
        return;
    }
    auto i = init_event_pool();
    ESP_LOGI(TAG, "创建事件池完毕，事件总数：%d", i);

    if (!create_event_handle_task()) {
        vQueueDelete(m_async_queue);
        delete_event_pool();
        ESP_LOGE(TAG, "创建LWIP事件处理进程失败.");
        return;
    }
}

Async::~Async()
{
    delete_event_pool();
    vQueueDelete(m_async_queue);
    m_async_queue = nullptr;
    vQueueDelete(m_event_pool);
    m_event_pool = nullptr;
    vTaskDelete(nullptr);
    m_async_task = nullptr;
}

/// @brief 创建事件处理进程
/// @return 创建成功时返回true
bool Async::create_event_handle_task()
{
    xTaskCreatePinnedToCore([](void* arg) {
        auto* async = reinterpret_cast<Async*>(arg);
        lwip_event_t* event;
        while (true) {
            if (xQueueReceive(async->m_async_queue, &event, portMAX_DELAY) == pdPASS) {
                async->handle_async_event(event);
                vTaskDelay(pdMS_TO_TICKS(1));
            }
        }
        ESP_LOGE(TAG, "LWIP事件处理进程运行越界.");
        vQueueDelete(async->m_async_queue);
        async->m_async_queue = nullptr;
        vTaskDelete(nullptr);
        async->m_async_task = nullptr;
    },
    "LwipEventHandle",
    CONFIG_ASYNC_TCP_WORKER_STACK,
    this,
    3,
    &m_async_task,
    CONFIG_ASYNC_TCP_RUNNING_CORE == -1 ? tskNO_AFFINITY : CONFIG_ASYNC_TCP_RUNNING_CORE
                           );

    return m_async_task != nullptr;
}

/// @brief 处理指定的LWIP事件
/// @param e lwip事件指针
void Async::handle_async_event(lwip_event_t* e)
{
    if (e->type == LWIP_TCP_ACCEPT) {
        reinterpret_cast<AsyncServer*>(e->arg)->handle_accepted_event(e->accep_client);
    } else {
        auto* client = reinterpret_cast<AsyncClient*>(e->arg);
        switch (e->type) {
        case LWIP_TCP_RECV:
            client->handle_received_event(e->recv_pcb, e->recv_pb, e->recv_err);
            break;
        case LWIP_TCP_FIN:
            client->handle_FIN_event(e->fin_pcb, e->fin_err);
            break;
        case LWIP_TCP_SENT:
            client->handle_sent_event(e->sent_pcb, e->sent_len);
            break;
        case LWIP_TCP_POLL:
            client->handle_poll_event(e->poll_pcb);
            break;
        case LWIP_TCP_ERROR:
            client->handle_error_event(e->err_err);
            break;
        case LWIP_TCP_CONNECTED:
            client->handle_connected_event(e->conn_pcb, e->conn_err);
            break;
        case LWIP_TCP_DNS:
            client->handle_DNS_found_event(&(e->dns_addr));
            break;
        default:
            ESP_LOGE(TAG, "未知类型的LWIP事件");
            break;
        }
        client->try_close_connection();
    }
    push_event_to_pool(e);
}

/// @brief 将LWIP事件发送到队列中
/// @param e LWIP事件指针
/// @return 发送成功返回true，发送失败时返回false
bool Async::send_event_to_queue(lwip_event_t* e)
{
    std::lock_guard<std::mutex> lock(m_queue_mutex);
    if (xQueueSend(m_async_queue, &e, portMAX_DELAY) != pdPASS) {
        ESP_LOGE(TAG, "发送事件到队列中失败，事件被丢弃！");
        return false;
    }
    return true;
}

uint8_t Async::init_event_pool()
{
    int i;
    std::lock_guard<std::mutex> lock(m_event_mutex);
    for (i = 0; i < CONFIG_EVENTS_QUEUE_LEN; i++) {
        auto* e = new lwip_event_t;
        if (e == nullptr) {
            ESP_LOGW(TAG, "创建事件%d失败,初始化池提前结束。", i);
            return i;
        }
        if (xQueueSend(m_event_pool, &e, portMAX_DELAY) != pdPASS) {
            ESP_LOGW(TAG, "事件%d: 初始化入池失败，释放事件", i);
            delete e;
            return i;
        }
    }
    return i;
}

void Async::delete_event_pool()
{
    std::lock_guard<std::mutex> lock1(m_event_mutex);
    std::lock_guard<std::mutex> lock2(m_queue_mutex);
    size_t pool_len = uxQueueMessagesWaiting(m_event_pool);
    size_t queue_len = uxQueueMessagesWaiting(m_async_queue);
    lwip_event_t* event;
    for (int i = 0; i < pool_len; i++) {
        xQueueReceive(m_event_pool, &event, 0);
        if (event != nullptr) {
            delete event;
        }
    }
    for (int i = 0; i < queue_len; i++) {
        xQueueReceive(m_async_queue, &event, 0);
        if (event != nullptr) {
            delete event;
        }
    }
}

void Async::push_event_to_pool(lwip_event_t* e)
{
    std::lock_guard<std::mutex> lock(m_event_mutex);
    if (xQueueSend(m_event_pool, &e, portMAX_DELAY) != pdPASS) {
        delete e;
        ESP_LOGW(TAG, "回收事件失败，删除事件！");
    }
}

lwip_event_t* Async::get_event_from_pool()
{
    std::lock_guard<std::mutex> lock(m_event_mutex);
    lwip_event_t* event = nullptr;
    xQueueReceive(m_event_pool, &event, pdMS_TO_TICKS(1));
    return event;
}